package com.sdk.es.http.service.base.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import com.sdk.es.http.conts.Conts;
import com.sdk.es.http.exception.SaasErrorEnum;
import com.sdk.es.http.exception.SaasException;
import com.sdk.es.http.kafka.EsProducer;
import com.sdk.es.http.service.base.IEsBaseService;
import com.sdk.es.http.util.EsUtil;
import com.sdk.es.sdk.entity.common.*;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregations;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wst
 * @date 2024/1/31
 *
 * 父类 Service 实现
 * @param <E>   具体索引实体
 */
@Slf4j
public abstract class EsBaseServiceImpl<E extends EsBaseEntity> implements IEsBaseService<E> {

    @Resource
    protected ElasticsearchOperations elasticsearchOperations;

    @Resource
    protected EsProducer esProducer;

    protected Class<E> eClazz;

    @PostConstruct
    private void init() {
        try {
            this.eClazz = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            log.debug("{} service init:{}", this.getClass().getSimpleName(), this.eClazz.getSimpleName());
        } catch (Exception e) {
            log.error("获取参数实体类型异常：{}", e.getMessage(), e);
        }
    }

    /**
     * 指定基础索引名，需要在子类复写
     */
    protected abstract String getEsIndex();

    /**
     * 查询索引
     * @return 搜索使用索引
     */
    protected IndexCoordinates searchIndex(String indexYearAndMonth,List<String> indexYearAndMonthList) {
        if (StrUtil.isBlank(this.getEsIndex())) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        //列表优先级最高
        if(indexYearAndMonthList != null && !indexYearAndMonthList.isEmpty()){
            List<String> indexList = new ArrayList<>();
            for(String yearAndMonth : indexYearAndMonthList){
                String index = this.getEsIndex() + Conts.ES_R + yearAndMonth;
                if(indexExists(index)){
                    indexList.add(this.getEsIndex() + Conts.ES_R + yearAndMonth);
                }else {
                    log.info("EsBaseServiceImpl.searchIndex索引不存在：{}",index);
                }
            }
            if(indexList.size() == 0){
                throw new SaasException(SaasErrorEnum.NO_SUCH_INDEX);
            }
            String[] stringArray = indexList.toArray(new String[0]);
            return IndexCoordinates.of(stringArray);
        }
        //单个优先级第二
        if(StrUtil.isNotBlank(indexYearAndMonth)){
            return EsUtil.get(this.getEsIndex(),indexYearAndMonth);
        }
        //全部优先级最低
        return EsUtil.getSplice(this.getEsIndex());
    }

    /**
     * 判断索引是否存在
     * @param indexName
     * @return
     */
    public boolean indexExists(String indexName) {
        return elasticsearchOperations.indexOps(IndexCoordinates.of(indexName)).exists();
    }
    @Override
    public E save(E req) {
        // 防错
        req.setId(null);
        E entity = elasticsearchOperations.save(req);
        if (entity.getId() == null) {
            log.error("BaseServiceImpl.save新增失败:{}", req);
            throw new SaasException(SaasErrorEnum.SAVE_ERROR);
        }
        log.info("BaseServiceImpl.save成功ID:{},索引:{}", entity.getId(),entity.getIndex());
        return entity;
    }

    @Override
    public void saveAsync(E req) {
        esProducer.sendSave(this.getEsIndex(), req);
    }

    @Override
    public List<E> saveBatch(List<E> list) {
        // 防错
        for (E entity : list) {
            entity.setId(null);
        }
        List<E> resultList = (List<E>) elasticsearchOperations.save(list);
        //只要有一个成功就返回所有成功
        boolean success = false;
        for (E entity : resultList) {
            if (entity.getId() == null) {
                log.error("BaseServiceImpl.saveBatch新增失败:{}", entity);
            } else {
                log.info("BaseServiceImpl.saveBatch成功ID:{},索引:{}", entity.getId(),entity.getIndex());
                success = true;
            }
        }
        //全部失败返回失败
        if (!success) {
            throw new SaasException(SaasErrorEnum.SAVE_ERROR);
        }
        return resultList;
    }

    @Override
    public void saveBatchAsync(List<E> list) {
        for (E r : list) {
            esProducer.sendSave(this.getEsIndex(), r);
        }
    }

    private SearchHit<E> searchById(E req) {
        if (StrUtil.isBlank(req.getId())) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        Class clazz = req.getClass();
        NativeQuery nativeQuery = new NativeQueryBuilder().withQuery(QueryBuilders.ids().values(req.getId()).build()._toQuery()).build();
        SearchHit<E> searchHit = elasticsearchOperations.searchOne(nativeQuery, clazz, this.searchIndex(null,null));
        if (searchHit == null) {
            throw new SaasException(SaasErrorEnum.NOT_FOUND);
        }
        return searchHit;
    }

    @Override
    public void update(E req) {
        SearchHit<E> searchHit = this.searchById(req);
        E old = searchHit.getContent();
        if (old == null) {
            throw new SaasException(SaasErrorEnum.NOT_FOUND);
        }
        BeanUtil.copyProperties(req, old, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        UpdateResponse updateResponse = elasticsearchOperations.update(old, EsUtil.get(searchHit.getIndex()));
        log.info("BaseServiceImpl.update更新结果:{},索引:{}", JSONUtil.toJsonStr(updateResponse),searchHit.getIndex());
    }

    @Override
    public void updateAsync(E req) {
        if (StrUtil.isBlank(req.getId())) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        esProducer.sendUpdate(this.getEsIndex(), req);
    }

    @Override
    public void delete(E req) {
        SearchHit<E> searchHit = this.searchById(req);
        E old = searchHit.getContent();
        if (old == null) {
            throw new SaasException(SaasErrorEnum.NOT_FOUND);
        }
        String deletedId = elasticsearchOperations.delete(req.getId(), EsUtil.get(searchHit.getIndex()));
        log.info("BaseServiceImpl.delete删除结果:{},索引:{}", deletedId,searchHit.getIndex());
    }

    @Override
    public void deleteAsync(E req) {
        if (StrUtil.isBlank(req.getId())) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        esProducer.sendDelete(this.getEsIndex(), req);
    }

    @Override
    public E getById(E req) {
        SearchHit<E> searchHit = this.searchById(req);
        E entity = searchHit.getContent();
        if (entity == null) {
            throw new SaasException(SaasErrorEnum.NOT_FOUND);
        }
        return entity;
    }

    @Override
    public E getOne(EsBaseParams<E> req) {
        List<E> resultList = this.getList(req);
        if (resultList.isEmpty()) {
            throw new SaasException(SaasErrorEnum.NOT_FOUND);
        }
        if (resultList.size() != 1) {
            throw new SaasException(SaasErrorEnum.FOUND_NOT_ONE);
        }
        return resultList.get(0);
    }

    @Override
    public List<E> getList(EsBaseParams<E> req) {
        if (null == this.eClazz) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        NativeQuery nativeQuery = EsUtil.toNativeQuery(req);
        SearchHits<E> searchHits = elasticsearchOperations.search(nativeQuery,
                this.eClazz,
                this.searchIndex(req.getIndexYearAndMonth(),req.getIndexYearAndMonthList()));
        return this.toList(searchHits);
    }

    @Override
    public EsPageResult<E> page(EsPageReq<E> esPageReq) {
        if (null == this.eClazz) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        IndexCoordinates indexCoordinates = this.searchIndex(esPageReq.getReq().getIndexYearAndMonth(),esPageReq.getReq().getIndexYearAndMonthList());
        NativeQuery nativeQuery = EsUtil.toNativeQuery(esPageReq.getReq(), esPageReq.getPageSize(), esPageReq.getPageNum());
        Long total = elasticsearchOperations.count(nativeQuery, indexCoordinates);
        SearchHits<E> searchHits = elasticsearchOperations.search(nativeQuery, this.eClazz, indexCoordinates);
        return this.toEsPageResult(searchHits, total, esPageReq.getPageSize(), esPageReq.getPageNum());
    }
    @Override
    public Long count(EsBaseParams<E> req) {
        if (null == this.eClazz) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        NativeQuery nativeQuery = EsUtil.toNativeQuery(req);
        return elasticsearchOperations.count(nativeQuery, this.searchIndex(req.getIndexYearAndMonth(),req.getIndexYearAndMonthList()));
    }

    @Override
    public List<GroupByResp> groupBy(EsBaseParams<E> req) {
        groupByReqcheck(req);
        //构建查询参数
        BoolQuery.Builder builder = EsUtil.toBoolQueryBuilder(req);
        List<GroupByResp> groupByRespList = new ArrayList<>();
        if(req.getGroupByFieldNameList().size() == 1){
            oneGroupBy(groupByRespList,builder,req.getGroupByFieldNameList(),1,EsUtil.MAX_RECORD,req.getIndexYearAndMonth(),req.getIndexYearAndMonthList());
        }else if(req.getGroupByFieldNameList().size() == 2){
            secGroupBy(groupByRespList,builder,req.getGroupByFieldNameList(),1,EsUtil.MAX_RECORD,req.getIndexYearAndMonth(),req.getIndexYearAndMonthList());
        }else if(req.getGroupByFieldNameList().size() == 3){
            thrGroupBy(groupByRespList,builder,req.getGroupByFieldNameList(),1,EsUtil.MAX_RECORD,req.getIndexYearAndMonth(),req.getIndexYearAndMonthList());
        }
        return groupByRespList;
    }
    @Override
    public EsPageResult<GroupByResp> groupByPage(EsPageReq<E> esPageReq) {
        groupByReqcheck(esPageReq.getReq());
        //构建查询参数
        BoolQuery.Builder builder = EsUtil.toBoolQueryBuilder(esPageReq.getReq());
        List<GroupByResp> groupByRespList = new ArrayList<>();
        Long total = 0L;
        if(esPageReq.getReq().getGroupByFieldNameList().size() == 1){
            total = oneGroupBy(groupByRespList,builder,esPageReq.getReq().getGroupByFieldNameList(),esPageReq.getPageNum(),esPageReq.getPageSize(),esPageReq.getReq().getIndexYearAndMonth(), esPageReq.getReq().getIndexYearAndMonthList());
        }else if(esPageReq.getReq().getGroupByFieldNameList().size() == 2){
            total = secGroupBy(groupByRespList,builder,esPageReq.getReq().getGroupByFieldNameList(),esPageReq.getPageNum(),esPageReq.getPageSize(),esPageReq.getReq().getIndexYearAndMonth(), esPageReq.getReq().getIndexYearAndMonthList());
        }else if(esPageReq.getReq().getGroupByFieldNameList().size() == 3){
            total = thrGroupBy(groupByRespList,builder,esPageReq.getReq().getGroupByFieldNameList(),esPageReq.getPageNum(),esPageReq.getPageSize(),esPageReq.getReq().getIndexYearAndMonth(), esPageReq.getReq().getIndexYearAndMonthList());
        }
        Long pageSizeLong = esPageReq.getPageSize().longValue();
        //计算总页数
        Long pages = total / pageSizeLong;
        if (total % pageSizeLong != 0) {
            pages = pages + 1;
        }
        return EsPageResult.of(groupByRespList, total, esPageReq.getPageSize(), esPageReq.getPageNum(), pages);
    }
    /**
     * 参数校验
     * @param req
     */
    private void groupByReqcheck(EsBaseParams<E> req) {
        //判断分组参数是否为空
        if(req.getGroupByFieldNameList() == null || req.getGroupByFieldNameList().size() == 0 || req.getGroupByFieldNameList().size() > 3){
            throw new SaasException(SaasErrorEnum.PARAM_NULL_ERROR);
        }
        //判断分组参数是否合法
        Field[] fields = ReflectUtil.getFields(req.getEntity().getClass());
        List<String> fieldNameList = new ArrayList<>();
        for(Field field : fields) {
            String fieldName = field.getName();
            fieldNameList.add(fieldName);
        }
        for(String s : req.getGroupByFieldNameList()){
            if(!fieldNameList.contains(s)){
                throw new SaasException(SaasErrorEnum.PARAM_DETAIL_ERROR,s);
            }
            if(Conts.ID.equals(s)){
                throw new SaasException(SaasErrorEnum.GROUP_BY_ID_ERROR);
            }
        }
        //处理参数
        for (int i = 0; i < req.getGroupByFieldNameList().size(); i++) {
            String s = req.getGroupByFieldNameList().get(i);
            //判断是否要拼接keyword,字符串的统一加keyword
            for(Field f : fields){
                if(f.getName().equals(s) && String.class.getTypeName().equals(f.getType().getTypeName())){
                    req.getGroupByFieldNameList().set(i,s + Conts.ES_KEYWORD);
                }
            }
        }
    }

    /**
     * 最大返回一千记录
     */
    private Long thrGroupBy(List<GroupByResp> groupByRespList, BoolQuery.Builder builder, List<String> groupByFieldNameList, Integer pageNum, Integer pageSize, String indexYearAndMonth, List<String> indexYearAndMonthList) {
        Long total = 0L;
        Long currentPageNoStart = (long) ((pageNum-1) * pageSize);
        Long currentPageNoEnd = currentPageNoStart + pageSize;
        Aggregation thrAgg = AggregationBuilders.terms().field(groupByFieldNameList.get(2)).size(10000).build()._toAggregation();
        String thrName = Conts.GROUP_BY_PREFIX + groupByFieldNameList.get(2);
        Aggregation secAgg = new Aggregation.Builder()
                .terms(AggregationBuilders.terms().field(groupByFieldNameList.get(1)).size(10000).build())
                .aggregations(new HashMap<>() {{put(thrName, thrAgg);
                }}).build();
        String secName = Conts.GROUP_BY_PREFIX + groupByFieldNameList.get(1);
        Aggregation oneAgg = new Aggregation.Builder()
                .terms(AggregationBuilders.terms().field(groupByFieldNameList.get(0)).size(10000).build())
                .aggregations(new HashMap<>() {{put(secName, secAgg);
                }}).build();
        String oneName = Conts.GROUP_BY_PREFIX + groupByFieldNameList.get(0);
        NativeQuery nativeQuery = new NativeQueryBuilder()
                .withQuery(builder.build()._toQuery())
                .withAggregation(oneName, oneAgg)
                .withMaxResults(0)
                .build();
        SearchHits<E> searchHits = elasticsearchOperations.search(nativeQuery,
                this.eClazz, this.searchIndex(indexYearAndMonth,indexYearAndMonthList));
        if (searchHits.hasAggregations()) {
            ElasticsearchAggregations elasticsearchAggregations = (ElasticsearchAggregations) searchHits.getAggregations();
            //转泛型,兼容字符串和数值型得列表
            EsBuckets oneBuckets = new EsBuckets<>();
            toT(elasticsearchAggregations.aggregationsAsMap().get(oneName).aggregation().getAggregate(),oneBuckets);
            //循环
            for(Object oneObj : oneBuckets.getT()){
                EsBuckets secBuckets = new EsBuckets<>();
                String onekey = toEsBuckets(oneObj,secName,secBuckets);
                for (Object secObj : secBuckets.getT()) {
                    EsBuckets thrBuckets = new EsBuckets<>();
                    String seckey = toEsBuckets(secObj,thrName,thrBuckets);
                    for(Object thrObj : thrBuckets.getT()){
                        //处理分页
                        if (total >= currentPageNoStart && total < currentPageNoEnd) {
                            GroupByResp groupByResp = new GroupByResp();
                            if(thrObj instanceof StringTermsBucket){
                                StringTermsBucket stringTermsBucket = (StringTermsBucket) thrObj;
                                groupByResp.setCount(stringTermsBucket.docCount());
                                groupByResp.setKeyList(List.of(onekey,seckey,stringTermsBucket.key().stringValue()));
                            }else {
                                LongTermsBucket longTermsBucket = (LongTermsBucket) thrObj;
                                groupByResp.setCount(longTermsBucket.docCount());
                                groupByResp.setKeyList(List.of(onekey,seckey,String.valueOf(longTermsBucket.key())));
                            }
                            groupByRespList.add(groupByResp);
                        }
                        total++;
                    }
                }
            }
        }
        return total;
    }
    /**
     * 最大返回一千记录
     */
    private Long secGroupBy(List<GroupByResp> groupByRespList, BoolQuery.Builder builder, List<String> groupByFieldNameList, Integer pageNum, Integer pageSize, String indexYearAndMonth, List<String> indexYearAndMonthList) {
        Long total = 0L;
        Long currentPageNoStart = (long) ((pageNum-1) * pageSize);
        Long currentPageNoEnd = currentPageNoStart + pageSize;
        Aggregation secAgg = AggregationBuilders.terms().field(groupByFieldNameList.get(1)).size(10000).build()._toAggregation();
        String secName = Conts.GROUP_BY_PREFIX + groupByFieldNameList.get(1);
        Aggregation oneAgg = new Aggregation.Builder()
                .terms(AggregationBuilders.terms().field(groupByFieldNameList.get(0)).size(10000).build())
                .aggregations(new HashMap<>() {{put(secName, secAgg);
                }}).build();
        String oneName = Conts.GROUP_BY_PREFIX + groupByFieldNameList.get(0);
        NativeQuery nativeQuery = new NativeQueryBuilder()
                .withQuery(builder.build()._toQuery())
                .withAggregation(oneName, oneAgg)
                .withMaxResults(0)
                .build();
        SearchHits<E> searchHits = elasticsearchOperations.search(nativeQuery,
                this.eClazz, this.searchIndex(indexYearAndMonth,indexYearAndMonthList));
        if (searchHits.hasAggregations()) {
            ElasticsearchAggregations elasticsearchAggregations = (ElasticsearchAggregations) searchHits.getAggregations();
            //转泛型,兼容字符串和数值型得列表
            EsBuckets oneBuckets = new EsBuckets<>();
            toT(elasticsearchAggregations.aggregationsAsMap().get(oneName).aggregation().getAggregate(),oneBuckets);
            //循环
            log.info("oneBuckets的伟大伟大：{}",oneBuckets.getT().size());
            for(Object oneObj : oneBuckets.getT()){
                EsBuckets secBuckets = new EsBuckets<>();
                String onekey = toEsBuckets(oneObj,secName,secBuckets);
                for (Object secObj :  secBuckets.getT()) {
                    log.info("secBuckets的伟大伟大：{}",secBuckets.getT().size());
                    //处理分页
                    if (total >= currentPageNoStart && total < currentPageNoEnd) {
                        GroupByResp groupByResp = new GroupByResp();
                        if(secObj instanceof StringTermsBucket){
                            StringTermsBucket stringTermsBucket = (StringTermsBucket) secObj;
                            groupByResp.setCount(stringTermsBucket.docCount());
                            groupByResp.setKeyList(List.of(onekey,stringTermsBucket.key().stringValue()));
                        }else {
                            LongTermsBucket longTermsBucket = (LongTermsBucket) secObj;
                            groupByResp.setCount(longTermsBucket.docCount());
                            groupByResp.setKeyList(List.of(onekey,String.valueOf(longTermsBucket.key())));
                        }
                        groupByRespList.add(groupByResp);
                    }
                    total++;
                }
            }
        }
        return total;
    }

    /**
     * 最大返回一千记录
     */
    public Long oneGroupBy(List<GroupByResp> groupByRespList, BoolQuery.Builder builder, List<String> groupByFieldNameList, Integer pageNum, Integer pageSize, String indexYearAndMonth, List<String> indexYearAndMonthList) {
        Long total = 0L;
        Long currentPageNoStart = (long) ((pageNum-1) * pageSize);
        Long currentPageNoEnd = currentPageNoStart + pageSize;
        Aggregation aggregation = AggregationBuilders.terms().field(groupByFieldNameList.get(0)).size(65536).build()._toAggregation();
        String name = Conts.GROUP_BY_PREFIX + groupByFieldNameList.get(0);
        NativeQuery nativeQuery = new NativeQueryBuilder()
                    .withQuery(builder.build()._toQuery())
                    .withAggregation(name, aggregation)
                    .withMaxResults(0)
                    .build();
        SearchHits<E> searchHits = elasticsearchOperations.search(nativeQuery,
                this.eClazz, this.searchIndex(indexYearAndMonth,indexYearAndMonthList));
        if (searchHits.hasAggregations()) {
            ElasticsearchAggregations elasticsearchAggregations = (ElasticsearchAggregations) searchHits.getAggregations();
            //转泛型,兼容字符串和数值型得列表
            EsBuckets esBuckets = new EsBuckets<>();
            toT(elasticsearchAggregations.aggregationsAsMap().get(name).aggregation().getAggregate(),esBuckets);
            //循环遍历
            for(Object o : esBuckets.getT()){
                //处理分页
                if (total >= currentPageNoStart && total < currentPageNoEnd) {
                    GroupByResp groupByResp = new GroupByResp();
                    if(o instanceof StringTermsBucket){
                        StringTermsBucket stringTermsBucket = (StringTermsBucket) o;
                        groupByResp.setCount(stringTermsBucket.docCount());
                        groupByResp.setKeyList(List.of(stringTermsBucket.key().stringValue()));
                    }else {
                        LongTermsBucket longTermsBucket = (LongTermsBucket) o;
                        groupByResp.setCount(longTermsBucket.docCount());
                        groupByResp.setKeyList(List.of(String.valueOf(longTermsBucket.key())));
                    }
                    groupByRespList.add(groupByResp);
                }
                total++;
            }
        }
        return total;
    }

    /**
     * 查询结果转换
     */
    public <T> EsPageResult<T> toEsPageResult(SearchHits<T> searchHits, Long total, Integer pageSize, Integer pageNum) {
        Long pageSizeLong = pageSize.longValue();
        //计算总页数
        Long pages = total / pageSizeLong;
        if (total % pageSizeLong != 0) {
            pages = pages + 1;
        }
        return EsPageResult.of(toList(searchHits), total, pageSize, pageNum, pages);
    }

    public <T> List<T> toList(SearchHits<T> searchHits) {
        return searchHits.hasSearchHits() ? searchHits.get().map(SearchHit::getContent).collect(Collectors.toList())
                : Collections.emptyList();
    }
    /**
     * 将buckets列表转成泛型，并获取当前层级分组的key
     */
    private String toEsBuckets(Object obj, String nextName, EsBuckets nextBuckets) {
        String key;
        if(obj instanceof StringTermsBucket){
            StringTermsBucket stringTermsBucket = (StringTermsBucket) obj;
            key = stringTermsBucket.key().stringValue();
            toT(stringTermsBucket.aggregations().get(nextName),nextBuckets);
        }else {
            LongTermsBucket longTermsBucket = (LongTermsBucket) obj;
            key = String.valueOf(longTermsBucket.key());
            toT(longTermsBucket.aggregations().get(nextName),nextBuckets);
        }
        return key;
    }

    /**
     * 将buckets列表转成泛型
     */
    private void toT(Aggregate aggregate,EsBuckets esBuckets) {
        if(aggregate.isSterms()){
            esBuckets.setT(aggregate.sterms().buckets().array());
        }else if(aggregate.isLterms()){
            esBuckets.setT(aggregate.lterms().buckets().array());
        }else {
            log.error("垃圾es不支持得类型，cnm:{}",aggregate);
            throw new SaasException(SaasErrorEnum.INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public Double sum(EsBaseParams<E> req) {
        if (null == this.eClazz) {
            throw new SaasException(SaasErrorEnum.PARAM_ERROR);
        }
        //参数校验
        if(StrUtil.isBlank(req.getSumFieldName())){
            throw new SaasException(SaasErrorEnum.PARAM_NULL_ERROR);
        }
        //判断分组参数是否合法
        Field[] fields = ReflectUtil.getFields(req.getEntity().getClass());
        List<String> fieldNameList = new ArrayList<>();
        for(Field field : fields) {
            String fieldName = field.getName();
            fieldNameList.add(fieldName);
            if(req.getSumFieldName().equals(fieldName) && String.class.getTypeName().equals(field.getType().getTypeName())){
                throw new SaasException(SaasErrorEnum.STRING_SUM_ERROR,req.getSumFieldName());
            }
            if(req.getSumFieldName().equals(fieldName) && LocalDateTime.class.getTypeName().equals(field.getType().getTypeName())){
                throw new SaasException(SaasErrorEnum.DATE_SUM_ERROR,req.getSumFieldName());
            }
        }
        //判断参数是否存在
        if(!fieldNameList.contains(req.getSumFieldName())){
            throw new SaasException(SaasErrorEnum.PARAM_DETAIL_ERROR,req.getSumFieldName());
        }
        //构建查询参数
        BoolQuery.Builder builder = EsUtil.toBoolQueryBuilder(req);
        //聚合sum查询
        Aggregation aggregation = AggregationBuilders.sum().field(req.getSumFieldName()).build()._toAggregation();
        String name = Conts.SUM_PREFIX + req.getSumFieldName();
        NativeQuery nativeQuery = new NativeQueryBuilder()
                .withQuery(builder.build()._toQuery())
                .withAggregation(name, aggregation)
                .withMaxResults(0)
                .build();
        SearchHits<E> searchHits = elasticsearchOperations.search(nativeQuery,this.eClazz, this.searchIndex(req.getIndexYearAndMonth(),req.getIndexYearAndMonthList()));
        if (searchHits.hasAggregations()) {
            ElasticsearchAggregations elasticsearchAggregations = (ElasticsearchAggregations) searchHits.getAggregations();
            SumAggregate sumAggregate = elasticsearchAggregations.aggregationsAsMap().get(name).aggregation().getAggregate().sum();
            return sumAggregate.value();
        }else {
            throw new SaasException(SaasErrorEnum.SUM_ERROR,req.getSumFieldName());
        }
    }
}
